class RadarConfigurator:
    def __init__(self, start_frequency_GHz, frequency_slope_MHzPus, sampling_rate_MsPs, number_of_samples,
                 number_of_chirp_loops, idle_time_us, adc_valid_start_time_us, ramp_end_time_us, frame_periodicity_ms,
                 num_rx_antennas, num_tx_antennas):
        self.start_frequency = start_frequency_GHz * 1e9  # GHz to Hz
        self.frequency_slope = frequency_slope_MHzPus * 1e6 * 1e6  # MHz/µs to Hz/s
        self.sampling_rate = sampling_rate_MsPs * 1e6  # Ms/s to Hz
        self.number_of_samples = number_of_samples
        self.number_of_chirp_loops = number_of_chirp_loops
        self.idle_time = idle_time_us * 1e-6  # µs to s
        self.adc_valid_start_time = adc_valid_start_time_us * 1e-6  # µs to s
        self.ramp_end_time = ramp_end_time_us * 1e-6  # µs to s
        self.frame_periodicity = frame_periodicity_ms * 1e-3  # ms to s
        self.num_rx_antennas = num_rx_antennas
        self.num_tx_antennas = num_tx_antennas
        self.num_virtual_rx_antennas = num_rx_antennas * num_tx_antennas
        self.max_tx_antenna_gain = 5.2

    def calculate_outputs(self):
        c = 299792458  # Speed of light in m/s
        Tc = self.number_of_samples / self.sampling_rate # Chirp time in seconds
        f0 = self.start_frequency
        B = self.frequency_slope * Tc  # Bandwidth in Hz
        fs = self.sampling_rate
        N = self.number_of_samples
        M = self.number_of_chirp_loops
        
        # Max Beat Frequency
        ifmax = self.sampling_rate * 0.8
        
        Tr = self.num_tx_antennas * (self.idle_time + self.ramp_end_time)
        
        # Carrier Frequency
        fc = f0 + self.frequency_slope * self.adc_valid_start_time +  B / 2

        # Maximum Range
        Rmax = c * ifmax / (2 * self.frequency_slope)

        # Range Resolution
        Rres = c / (2 * B)

        # Maximum Velocity
        vmax = c / (4 * Tr * fc)

        # Velocity Resolution
        vres = 2 * vmax / self.number_of_chirp_loops

        # Chirp Time
        chirp_time = Tc

        # Chirp Repetition Period
        chirp_repetition_period = Tr

        # RF Duty Cycle
        rf_duty_cycle = M * Tr / self.frame_periodicity * 100
        
        # Compliance Chirp Time
        compliance_chirp_time = (self.ramp_end_time + self.idle_time) * self.num_tx_antennas * self.number_of_chirp_loops

        # Active Chirping Time
        active_chirping_time = self.ramp_end_time  * self.num_tx_antennas * self.number_of_chirp_loops

        # Valid Sweep Bandwidth
        valid_sweep_bandwidth = B

        # End Frequency
        fend = f0 + self.frequency_slope * self.ramp_end_time

        return {
            'Maximum Range (m)': Rmax,
            'Range Resolution (m)': Rres,
            'Maximum Velocity, vmax (m/s)': vmax,
            'Velocity Resolution (m/s)': vres,
            'Chirp Time, Tc (µs)': chirp_time * 1e6,
            'Chirp Repetition Period, Tr (µs)': chirp_repetition_period * 1e6,
            'RF Duty Cycle (%)': rf_duty_cycle,
            'Compliance Chirp Time (ms)': compliance_chirp_time * 1e3,
            'Active Chirping Time (ms)': active_chirping_time * 1e3,
            'Max Beat Frequency, IFmax (MHz)': ifmax / 1e6,
            'Valid Sweep Bandwidth, B (MHz)': valid_sweep_bandwidth / 1e6,
            'Carrier Frequency, fc (GHz)': fc / 1e9,
            'End Frequency (GHz)': fend / 1e9
        }

# Example usage
config = RadarConfigurator(
    start_frequency_GHz=77,
    frequency_slope_MHzPus=20.910,
    sampling_rate_MsPs=3,
    number_of_samples=107,
    number_of_chirp_loops=27,
    idle_time_us=2,
    adc_valid_start_time_us=6.4,
    ramp_end_time_us=43.070,
    frame_periodicity_ms=100,
    num_rx_antennas=4,
    num_tx_antennas=2
)

outputs = config.calculate_outputs()
for key, value in outputs.items():
    print(f"{key}: {value}")